#ifndef LIST_H_INCLUDED
#define LIST_H_INCLUDED

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "util.h"

#define MAKE_LIST(STRUCT_NAME, PREFIX, ARRAY_TYPE, MAKE_COPY, FREE_ITEM, EQUALS) \
    struct s_ ## STRUCT_NAME						\
    {                                                                   \
        ARRAY_TYPE* array;                                              \
        int count;                                                      \
        int size;                                                       \
    } ;                                                                 \
                                                                        \
    typedef struct s_ ## STRUCT_NAME STRUCT_NAME;                       \
                                                                        \
    STRUCT_NAME* PREFIX ## _create(int size)                            \
    {                                                                   \
        if (size <= 0)                                                  \
        {                                                               \
            die("Initial size of array list must be > 0. Got %d\n", size); \
        }                                                               \
        STRUCT_NAME* result = malloc(sizeof(STRUCT_NAME));              \
        result->array = malloc(sizeof(ARRAY_TYPE)*size);                \
        result->count = 0;                                              \
        result->size = size;                                            \
        return result;                                                  \
    }                                                                   \
                                                                        \
    void PREFIX ## _resize(STRUCT_NAME* list)                           \
    {                                                                   \
        int newsize = list->size*2;                                     \
        ARRAY_TYPE* newarray = malloc(sizeof(ARRAY_TYPE)*newsize);      \
        int i;                                                          \
        for (i=0; i < list->size; i += 1)                               \
        {                                                               \
            newarray[i] = list->array[i];                               \
        }                                                               \
        list->size = newsize;                                           \
        free(list->array);                                              \
        list->array = newarray;                                         \
    }                                                                   \
                                                                        \
    void PREFIX ## _push(STRUCT_NAME* list, const ARRAY_TYPE item)      \
    {                                                                   \
        list->array[list->count] = MAKE_COPY(item);                     \
        list->count += 1;                                               \
        if (list->count >= list->size - 1)                              \
        {                                                               \
            PREFIX ## _resize(list);                                    \
        }                                                               \
    }                                                                   \
                                                                        \
    ARRAY_TYPE PREFIX ## _pop(STRUCT_NAME* list)                        \
    {                                                                   \
        list->count -= 1;                                               \
        return list->array[list->count];                                \
    }                                                                   \
                                                                        \
    void PREFIX ## _free(STRUCT_NAME* list)                             \
    {                                                                   \
        int len = list->count;                                          \
        int i;                                                          \
        for(i = 0; i < len; i += 1)                                     \
        {                                                               \
            FREE_ITEM(list->array[i]);                                  \
        }                                                               \
        free(list);                                                     \
    }                                                                   \
                                                                        \
    bool PREFIX ## _find(STRUCT_NAME* list, ARRAY_TYPE item)            \
    {                                                                   \
        int i;                                                          \
        for (i = 0; i < list->count; i += 1)                            \
        {                                                               \
            if (EQUALS(list->array[i], item))                           \
            {                                                           \
                return true;                                            \
            }                                                           \
        }                                                               \
        return false;                                                   \
    }


// Create functions for char* arraylist
char* List_copy(const char* item)
{
    if (item == NULL)
    {
        return NULL;
    }
    int len = strlen(item) + 1;
    char* copy = malloc(len*sizeof(char));
    CHECK_PTR(copy);
    strcpy(copy, item);
    return copy;
}

int List_equals(char* c, char* d)
{
    return strcmp(c,d) == 0;
}

void _myfree(char* c)
{
    free(c);
}

MAKE_LIST(List, List, char*, List_copy, _myfree, List_equals);

#endif //LIST_H_INCLUDED
